home *** CD-ROM | disk | FTP | other *** search
/ Gekkan Dennou Club 140 / Gekkan Dennou Club - 2000.1 Vol. 140 (Japan).7z / Gekkan Dennou Club - 2000.1 Vol. 140 (Japan) (Track 1).bin / tools / dshell / dsh333bs.lzh / menu2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-28  |  5.2 KB  |  259 lines

  1. /*
  2.     dshell    v3
  3.  
  4.     ローカルメニュー (v3.33~)
  5. */
  6.  
  7. #include    "dsh.h"
  8.  
  9.  
  10. #define    MINWIDTH    8    // メニュー最小桁幅
  11. #define    MAXWIDTH    48    // メニュー最大桁幅
  12. #define    MAXHEIGHT    12    // 一度に表示するメニュー項目の最大数 (越える場合はスクロール)
  13.  
  14. typedef struct menuItem {
  15.     struct menuItem *next;
  16.     void *str;    // メニュー項目文字列 (ただし, str[0] はフラグ)
  17. } MENUITEM;
  18.  
  19. typedef struct menu {
  20.     struct menu *prev;
  21.     MENUITEM *head;    // メニュー項目リスト
  22.     void *id;    // このメニューを定義したテキストのID
  23. } MENU;
  24.  
  25. static MENU *menuHead;
  26. static int nItem;    // メニュー項目の総数
  27. static int nMenu;    // メニューの総数
  28.  
  29.  
  30. /*
  31.     メニュー項目を追加する
  32. */
  33. int
  34. addMenuItem(void *id, const uchar *str)
  35. {
  36.     MENU *menu = menuHead;
  37.     MENUITEM *item, *itemP;
  38.  
  39.     item = malloc(sizeof(MENUITEM));
  40.     if (item == NULL)
  41.         return -1;
  42.     if (menu == NULL || menu->id != id) {
  43.         menu = malloc(sizeof(MENU));
  44.         if (menu == NULL)
  45.             return -1;
  46.         menu->prev = menuHead;
  47.         menu->head = item;
  48.         menu->id = id;
  49.         menuHead = menu;
  50.         nMenu++;
  51.     } else {
  52.         for (itemP = menu->head; itemP->next != NULL; itemP = itemP->next)
  53.             ;
  54.         itemP->next = item;
  55.     }
  56.     item->next = NULL;
  57.     item->str = str;
  58.     nItem++;
  59.  
  60.     return 0;
  61. }
  62.  
  63.  
  64. /*
  65.     定義したテキストの閲覧終了時に対応するメニューがあれば解放する
  66. */
  67. void
  68. freeMenu(void *id)
  69. {
  70.     MENU *menu = menuHead;
  71.     MENUITEM *item, *itemP;
  72.  
  73.     if (menu == NULL || menu->id != id)
  74.         return;
  75.     menuHead = menu->prev;
  76.     for (itemP = menu->head; itemP != NULL;) {
  77.         item = itemP;
  78.         itemP = itemP->next;
  79.         free(item);
  80.         nItem--;
  81.     }
  82.     free(menu);
  83.     nMenu--;
  84. }
  85.  
  86.  
  87. static int
  88. getStrWidth(const uchar *str)
  89. {
  90.     uchar *p = str;
  91.     uchar c;
  92.     int n = 1;
  93.  
  94.     while ((c = *p++) != '\0') {
  95.         if (iskanji1(c)) {
  96.             p++;
  97.             if (c == 0x80 || c >= 0xf0)
  98.                 n++;
  99.         }
  100.     }
  101.     return (p - str) - n;
  102. }
  103.  
  104.  
  105. static void
  106. drawMenu(int x, int y, uchar **items, int width, int n)
  107. {
  108.     while (--n >= 0)
  109.         B_PUTMES(3, x, y++, width - 1, (*items++) + 1);
  110. }
  111.  
  112.  
  113. /*
  114.     メニュー選択 (下メニューバー中の MENU を右クリックでオープン)
  115. */
  116. void
  117. localMenu(int sx)
  118. {
  119.     uchar **items;
  120.     MENU *menu;
  121.     MENUITEM *itemP;
  122.     uchar *command;
  123.     int n, len, width, height, base;
  124.     int x0, y0, gx0, gy0, gwidth;
  125.     uchar rollFlag = FALSE;
  126.     uchar bar[1 + MAXWIDTH + 1];    // フラグ,───,0
  127.     int mx, my, dx, dy, bl, br;
  128.     int m, mm, et;
  129.     uchar flag;
  130.     struct TREVPTR trevBuf;
  131.  
  132.     // リスト表現された複数メニューを連結してポインタ配列を作る (ちょいダサ)
  133.     if (nItem <= 0 || (items = malloc(sizeof(*items) * (nItem + nMenu))) == NULL) {
  134.         wait_mb_off();
  135.         return;
  136.     }
  137.     n = 0;
  138.     width = MINWIDTH;
  139.     for (menu = menuHead; menu != NULL;) {
  140.         for (itemP = menu->head; itemP != NULL; itemP = itemP->next) {
  141.             items[n++] = itemP->str;
  142.             len = getStrWidth(itemP->str + 1);
  143.             if (len > width)
  144.                 width = len;
  145.         }
  146.         menu = menu->prev;
  147.         if (menu != NULL)
  148.             items[n++] = bar;
  149.     }
  150.     items[n] = NULL;
  151.     width = (width + 1) & -2;
  152.     height = n;
  153.     if (height > MAXHEIGHT) {
  154.         height = MAXHEIGHT;
  155.         rollFlag = TRUE;
  156.     }
  157.     if (nMenu > 1) {
  158.         uchar *p = bar;
  159.         int i;
  160.  
  161.         *p++ = 0;
  162.         for (i = 0; i < width / 2; i++) {
  163.             *p++ = (uchar)(L'─' >> 8);
  164.             *p++ = (uchar)(L'─');
  165.         }
  166.         *p = '\0';
  167.     }
  168.     sx--;
  169.     x0 = sx - 1;
  170.     if (x0 + width + 2 > CWIDTH)
  171.         x0 = CWIDTH - width - 2;
  172.     y0 = 30 - height;
  173.     B_COLOR(5);
  174.     gx0 = (x0 << 3) - 4;
  175.     gy0 = y0 << 4;
  176.     gwidth = (width << 3) + 8;
  177.     trevBuf.vram_page = 0;
  178.     trevBuf.x = gx0;
  179.     trevBuf.x1 = gwidth;
  180.     trevBuf.y1 = 16;
  181.     if (rollFlag) {
  182.         y0--;
  183.         gy0 -= 16;
  184.         win_frame(x0 - 2, y0 - 2, x0 + width, 30, 0, sx);
  185.         B_PUTMES(3, x0 + width / 2 - 1, y0 - 1, 2 - 1, "▲");
  186.         B_PUTMES(3, x0 + width / 2 - 1, 29, 2 - 1, "▼");
  187.         msarea(gx0, gy0 - 16 + 1, gx0 + gwidth - 1, 511);
  188.     } else {
  189.         win_frame(x0 - 2, y0 - 1, x0 + width, 30, 0, sx);
  190.         msarea(gx0, gy0 + 1, gx0 + gwidth - 1, 511);
  191.     }
  192.     B_COLOR(3);
  193.     base = 0;
  194.     drawMenu(x0, y0, items + base, width, height);
  195.     wait_mb_off();
  196.     mm = -2;
  197.     et = 0;
  198.     flag = FALSE;
  199.     for (;;) {
  200.         p_time(0);
  201.         dmspos(&mx, &my);
  202.         if (my >= 30 * 16)
  203.             m = -2;
  204.         else
  205.             m = (my - gy0 + 16) / 16 - 1;
  206.         if (m != mm) {
  207.             if (mm > -2) {
  208.                 trevBuf.y = gy0 + mm * 16;
  209.                 TXREV(&trevBuf);
  210.             }
  211.             if (m > -2) {
  212.                 if (m == -1 || m == MAXHEIGHT || items[base + m][0]) {
  213.                     trevBuf.y = gy0 + m * 16;
  214.                     trevBuf.vram_page = 0;
  215.                     TXREV(&trevBuf);
  216.                 } else {
  217.                     m = -2;
  218.                 }
  219.             }
  220.             mm = m;
  221.         }
  222.         dmsstat(&dx, &dy, &bl, &br);
  223.         if (br) {
  224.             m = -2;
  225.             break;
  226.         }
  227.         if (bl) {
  228.             int ontime = d_ontime();
  229.             if (m == -1 && base > 0 && et < ontime) {
  230.                 base--;
  231.                 drawMenu(x0, y0, items + base, width, height);
  232.                 et = init_et(et ? ((B_SFTSNS() & 1) ? 0 : 5) : 40);
  233.             } else if (m == MAXHEIGHT && base < n - MAXHEIGHT && et < ontime) {
  234.                 base++;
  235.                 drawMenu(x0, y0, items + base, width, height);
  236.                 et = init_et(et ? ((B_SFTSNS() & 1) ? 0 : 5) : 40);
  237.             } else if (m >= 0 && m < MAXHEIGHT && items[base + m][0]) {
  238.                 break;
  239.             }
  240.         } else
  241.             et = 0;
  242.     }
  243.     msarea(0, 0, GWIDTH - 1, 511);
  244.     p_scr();
  245.     command = NULL;
  246.     if (m >= 0 && items[base + m][0]) {
  247.         command = items[base + m] + 1;
  248.         while (*command++ != '\0')
  249.             ;
  250.     }
  251.     free(items);
  252.     wait_mb_off();
  253.     if (command != NULL) {
  254.         dtype(command, TRUE);
  255.         p_fukki();
  256.         mouse(1);
  257.     }
  258. }
  259.